import wx
from zope import interface
import os, sys
from amara import binderytools

APPLICATION_INSTALL_DIR = os.environ.get('SIMPLEWATCHER_INSTALL')
if not APPLICATION_INSTALL_DIR:
    raise EnvironmentError("must set environment variable SIMPLEWATCHER_INSTALL")
sys.path.append('%s/lib' % APPLICATION_INSTALL_DIR)

from watch_builder.gui.watchobjects import base
from watch_builder.gui.evthandle import registrar
from watch_builder.builder import buildKlass
from watch_builder.gui import utils, dialogs, helpers
from watch_builder.gui.watchobjects import interfaces as wa_ints

class WatchObjectDropTarget(wx.PyDropTarget):
    def __init__(self, window, *args, **kwargs):
        # i normally use super here, but the examples
        # are using it directly, so we'll follow their lead for now
        wx.PyDropTarget.__init__(self)
        self._makeObjects()
        self.win = window


    def _makeObjects(self):
        self.data = base.SimpleWatcherDataObject()
        self.fileObject = wx.FileDataObject()
        comp = wx.DataObjectComposite()
        comp.Add(self.data)
        comp.Add(self.fileObject)
        self.comp = comp
        self.SetDataObject(self.comp)
    
    
    def OnEnter(self, x, y, d):
        return d

    def OnDrop(self, x, y):
        return True

    def OnDragOver(self, x, y, d):
        return d


    def OnDrop(self, x, y):
        return True
        

    def OnData(self, x, y, d):
        if self.GetData():
            doc = binderytools.bind_string(self.data.getObject())
            klass = doc.xml_xpath("//@klass")[0].nodeValue
            package = doc.xml_xpath("//@package")[0].nodeValue
            obj = buildKlass(package, klass)()
            obj.fromXml(doc.xml())
            self.handleDataPlacement(x, y, d, obj)
        return d


    def handleDataPlacement(self, x, y, d, obj):
        newx, newy = self.win.helper.findBestCoord((x, y), obj)
        if newx is None or newy is None:
            return
        self.win.setChild((newx, newy), obj)




class WatchObjectWindow(wx.Window):
    def __init__(self, parent, id=-1, *args, **kwargs):
        wx.Window.__init__(self, parent, id, style=wx.SUNKEN_BORDER)
        self.SetBackgroundColour(wx.WHITE)
        self.helper = helpers.WatchObjectWindowHelper(self)
        drop_target = WatchObjectDropTarget(self)
        self.SetDropTarget(drop_target)
        self._children = {}
        root = buildKlass("watch_builder.gui.watchobjects.base", "RootDataObject")()
        self.setChild((0,0), root)
        self.currentChild = root
        self.dragInProgress = False
        self.motionEventLocationStart = (0, 0)
        #registrar.register(self.OnMotion, wx.EVT_MOTION, self)
    

    def setChild(self, loc, child):
        bmp = wx.StaticBitmap(self, -1, child.image, loc, size=(40, 40))
        # this is intentionally destructive
        self._children[loc] = (child, bmp)
        func = self.helper.findContextMenuFuncFor(child)
        if func is not None:
            registrar.register(func, wx.EVT_RIGHT_UP, bmp)


    def delChild(self, child):
        loc_deleted = None
        for loc in self._children:
            maybe, bmp = self._children[loc]
            if maybe is child:
                loc_deleted = loc
                for grandchild in child._children:
                    self.delChild(grandchild)
                bmp.Destroy()
                parent = child._parent
                parent._children.remove(child)
        if loc_deleted:
            self._children[loc_deleted] = None
            self._children.pop(loc_deleted)


    def ContextEdit(self, event, inttype, title="Context Edit"):
        dialog = dialogs.ContextEdit(self, wx.NewId(), title=title, size=(350,200), child=self.currentChild)
        val = dialog.ShowModal()
        if val == wx.ID_OK:
            updaterFunc = self.helper.findUpdateFuncFor(self.currentChild)
            updaterArgs = {}
            for key in dialog.widgets.keys():
                updaterArgs[key] = dialog.widgets[key].GetValue()
            updaterFunc(self.currentChild, **updaterArgs)


    def ContextDelete(self, event):
        dialog = dialogs.ContextDelete(self, wx.NewId(), "Delete", size=(350,200))
        val = dialog.ShowModal()
        if val == wx.ID_OK:
            self.delChild(self.currentChild)

        dialog.Destroy()


    def ContextMenu(self, event, inttype):
        self.currentChild = self.helper.findNearestChild(event.GetPosition(), inttype)
        menu = wx.Menu()
        edit = wx.MenuItem(menu, wx.NewId(), "Edit")
        func = self.helper.findContextEditFuncFor(self.currentChild)
        if func is not None:
            registrar.register(func, wx.EVT_MENU, edit)
        menu.AppendItem(edit)
        if inttype is not wa_ints.IRootDataObject:
            delete = wx.MenuItem(menu, wx.NewId(), "Delete")
            registrar.register(self.ContextDelete, wx.EVT_MENU, delete)
            menu.AppendItem(delete)
        self.PopupMenu(menu)
        menu.Destroy()


    #def OnMotion(self, event):
        #if not event.Dragging():
        #    self.motionEventLocationStart = event.GetPosition()
        #if not self.dragInProgress and event.Dragging():
        #    self.currentChild = self.helper.findNearestChild(self.motionEventLocationStart, wa_ints.ISimpleWatcherDataObject)
        #    self.dragInProgress = True
        #    self.startDragDrop()
    
    
    #def startDragDrop(self):
        #print "DEBUG: we're starting drag drop"
        #drop_source = self.buildDropSource(self.currentChild)
        #print "DEBUG: we built drop source"
        #result = drop_source.DoDragDrop(wx.Drag_AllowMove)
        #print "DEBUG: we got result %s" % result
        #self.dragInProgress = False
        #if result == wx.DragMove:
            #self.Refresh()


    #def buildDropSource(self, child):
        #drop_source = wx.DropSource(self)
        #drop_source.SetData(child)
        #return drop_source    
    


class WatchObjectWorkspace(wx.Panel):
    """just to make it explicit that i'm using this panel to manage drop targets"""
    def __init__(self, parent, id=-1, *args, **kwargs):
        wx.Panel.__init__(self, parent, id)
        self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        
        view = WatchObjectWindow(self)
        sizer = wx.BoxSizer(wx.VERTICAL)
        
        sizer.Add(view, 1, wx.EXPAND | wx.ALL, 5)
        self.SetAutoLayout(True)
        self.SetSizer(sizer)



